import fs from "fs";
import { Block } from "./Block";

export class Blockchain {
    chain: Block[]; // 区块链
    difficulty: number; // 工作量证明难度
    dataPath: string; //区块链数据文件路径

    constructor (
        dataPath: string,
    ) {
        this.chain = [this.createGenesisBlock()];
        this.difficulty = 2;
        this.dataPath = dataPath;

        // 从文件中加载区块链
        this.loadChainFromFile();

        // 系统崩溃时，保存区块链到文件
        process.on('exit', () => {
            this.saveChainToFile();
        })
    }

    get height () {
        return this.chain.length;
    }

    // 创建创世区块
    createGenesisBlock () : Block {
        return new Block(0, '01/01/2020', 'Genesis block', '0');
    }

    // 获取最新区块
    getLatestBlock () : Block {
        return this.chain[this.chain.length - 1];
    }

    // 添加新区块
    addBlock (newBlock: Block) : void {
        newBlock.previousHash = this.getLatestBlock().hash;
        newBlock.mineBlock(this.difficulty);
        this.chain.push(newBlock);
        this.saveChainToFile();
    }

    // 验证区块链是否有效
    isChainValid (chain: Block[] = this.chain) : boolean {
        for (let i = 1; i < chain.length; i++) {
            const currentBlock = chain[i];
            const previousBlock = chain[i - 1];

            if (currentBlock.hash !== currentBlock.calculateHash()) {
                return false;
            }

            if (currentBlock.previousHash !== previousBlock.hash) {
                return false;
            }
        }
        return true;
    }

    // 保存区块到文件
    saveChainToFile () : void {
        console.log('Saving blockchain to file...');
        if (this.isChainValid() === false) {
            console.error('Blockchain is invalid.');
            return;
        }
        fs.writeFileSync(this.dataPath, JSON.stringify(this.chain, null, 2));
        console.log('Blockchain saved to file.');
    }

    // 从文件中加载区块链
    loadChainFromFile () : void {
        console.log('Loading blockchain from file...');
        try {
            if (!fs.existsSync(this.dataPath)) {
                console.error('Blockchain file not found.');
                return;
            }
            const loadedChain = JSON.parse(fs.readFileSync(this.dataPath, 'utf-8'));
            this.chain = loadedChain.map((data: any) => {
                const block = new Block(
                    data.index,
                    data.timestamp,
                    data.data,
                    data.previousHash
                )
                block.hash = data.hash;
                block.nonce = data.nonce;
                return block;
            })
            if (!this.isChainValid()) {
                console.error('Blockchain is invalid, discarding loaded data.');
                this.chain = [this.createGenesisBlock()];
                return;
            }
        } catch (e) {
            console.error('Error loading blockchain from file:', e)
        }
    }
}